package nconv.convert;
import nconv.utils.LogCenter;
import nconv.utils.Pair;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Map;

/**
 * @author xiaobyu
 * @created Mar 22, 2016
 * 
 */

public class ImageHandler {


	public static final String IDENTITY_COMMAND = "\"C:\\Program Files\\ImageMagick-6.9.3-Q16\\identify.exe\"";
	public static final String CONVERT_COMMAND = "\"C:\\Program Files\\ImageMagick-6.9.3-Q16\\convert.exe\"";

	private static final int MAX_PIXELS = 10_000_000;
	private static final int MAX_WIDTH = 1024;
	

	public static void convert(String srcName, String dstName, boolean deleteSrc) {
		convert(new File(srcName), new File(dstName), deleteSrc);
	}
	public static boolean convert(File srcFile, File dstFile, boolean deleteSrc) {
		Pair<Integer, Integer> dimension = getImageDimension(srcFile.getAbsolutePath());
		String resizeParam = " ";
		if (dimension != null) {
			LogCenter.log("File: " + srcFile.getName() + " size: " + dimension);
			int width = dimension.first;
			int height = dimension.second;
			int percent = 100;
			if (width * height > MAX_PIXELS) {
				percent = MAX_PIXELS * 100/ (width * height);
			}

			if (width * percent / 100 > MAX_WIDTH) {
				percent = MAX_WIDTH * 100/ width;
			}
			if (percent < 100) {
				resizeParam = " -resize " + percent + "% ";
			}
		}
		String cmd = CONVERT_COMMAND + resizeParam + srcFile.getAbsolutePath() +
				" " + dstFile.getAbsolutePath();
		boolean hasError = true;
		String errMsg = "";
		try {
			Process process = Runtime.getRuntime().exec(cmd);
			try {
				int retCode = process.waitFor();
				if (retCode != 0) {
					BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));

					String s = null;
					// Read diameterCommand errors
					while ((s = stdError.readLine()) != null) {
						errMsg += s;
					}
				} else {
					hasError = false;

				}
			} catch (InterruptedException e) {
				errMsg = e.getMessage();
			}
		} catch (Exception e) {
			errMsg = e.getMessage();
		}
		
		if (hasError) {
			System.err.println("Error while executing: " + cmd + ", details: " + errMsg);
			return false;
		} else {
			if (deleteSrc) {
				srcFile.delete();
			}
			return true;
		}
	}

	private static Pair<Integer, Integer> getImageDimension(String fileName) {
		String cmd = IDENTITY_COMMAND + " -format \"%[fx:w]x%[fx:h]\" " + fileName;
		Process process = null;
		try {
			process = Runtime.getRuntime().exec(cmd);
			try {
				int retCode = process.waitFor();
				if (retCode == 0) {
					BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));

					String s = null;
					if ((s = stdInput.readLine()) != null) {
						int width = Integer.parseInt(s.substring(0, s.indexOf('x')));
						int height = Integer.parseInt(s.substring(s.indexOf('x') + 1));
						return new Pair<Integer, Integer>(width, height);
					}
				}
			} catch (InterruptedException e) {
			}
		} catch (Exception e) {
		}

		System.err.println("Failed to get image dimension: " + fileName);
		return null;
	}

	private static String outputDir = "output/";
	private static String inputDir = "input/";

	public static void setOutputDir(String dir) {
		File f = new File(dir);
		outputDir = f.getAbsolutePath() + File.separator;
	}
	
	public static String getOutputDir() {
		return outputDir;
	}

	public static String getInputDir() {
		return inputDir;
	}

	public static void setInputDir(String dir) {
		File f = new File(dir);
		inputDir = f.getAbsolutePath() + File.separator;
	}

	public static boolean isSameFile(Map<String, Object> metaData, File file) {
		if (metaData == null) return false;

		try {
			int size = (int)metaData.get("size");
			if (size != file.length()) return false;

			Pair<Integer, Integer> dimension = getImageDimension(file.getAbsolutePath());
			int width = (int) metaData.get("width");
			int height = (int) metaData.get("height");
			if (dimension.first == width && dimension.second == height)
				return true;
		} catch (Exception e) {
			return false;
		}

		return false;
	}
}
